/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.geoviewer.jxmap.render;

import com.vividsolutions.jts.geom.Geometry;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.image.RenderedImage;
import nl.cloudfarming.client.geoviewer.Palette;
import org.geotools.coverage.grid.GeneralGridEnvelope;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.operation.builder.GridToEnvelopeMapper;
import org.geotools.renderer.lite.RendererUtilities;
import org.geotools.renderer.lite.gridcoverage2d.GridCoverageRenderer;
import org.geotools.styling.ChannelSelection;
import org.geotools.styling.ColorMap;
import org.geotools.styling.ContrastEnhancement;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.RasterSymbolizerImpl;
import org.geotools.styling.SLD;
import org.geotools.styling.SelectedChannelType;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.styling.StyleFactory;
import org.jdesktop.swingx.JXMapViewer;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.filter.FilterFactory2;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import org.openide.util.Exceptions;

/**
 * GridCoverage2DRenderer
 *
 *
 * @author Timon Veenstra
 */
public class GridCoverage2DRenderer implements RasterRenderer<GridCoverage2D> {

    private StyleFactory sf = CommonFactoryFinder.getStyleFactory(null);
    private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);

    @Override
    public void paint(Rectangle clientArea, Geometry geometry, GridCoverage2D raster, JXMapViewer mapViewer, Graphics2D graphics, Palette palette) {
        // skip painting is raster is empty
        if (raster == null) {
            return;
        }

//------------------------------------------------------------------------------
//-- S-1 working solution, shows black and white and with extra fields
//------------------------------------------------------------------------------

//        RenderedImage renderedImage = raster.getRenderedImage();
//
//        GridEnvelope gridEnvelope = new GeneralGridEnvelope(renderedImage, raster.getDimension());
//        Envelope userEnv = new GeneralEnvelope(clientArea);
//        GridToEnvelopeMapper envelopeMapper = new GridToEnvelopeMapper(gridEnvelope, userEnv);
//        graphics.drawRenderedImage(renderedImage, envelopeMapper.createAffineTransform());


//------------------------------------------------------------------------------
//-- /S-1
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- /S-2 shows black white image on map, symbolizer need to be enhanced
//------------------------------------------------------------------------------
        try {
            RenderedImage renderedImage = raster.getRenderedImage();
            Envelope userEnv = new GeneralEnvelope(clientArea);
            GridEnvelope gridEnvelope = new GeneralGridEnvelope(renderedImage, raster.getDimension());
            GridToEnvelopeMapper envelopeMapper = new GridToEnvelopeMapper(gridEnvelope, userEnv);



            com.vividsolutions.jts.geom.Envelope mapEnvelope = RendererUtilities.createMapEnvelope(clientArea, envelopeMapper.createAffineTransform());

            double minx = raster.getEnvelope2D().getMinX();
            double maxx = raster.getEnvelope2D().getMaxX();
            double miny = raster.getEnvelope2D().getMinY();
            double maxy = raster.getEnvelope2D().getMaxY();

            com.vividsolutions.jts.geom.Envelope rasterEnvelope = new com.vividsolutions.jts.geom.Envelope(minx,maxx,miny,maxy);

            GridCoverageRenderer renderer = new GridCoverageRenderer(DefaultGeographicCRS.WGS84, rasterEnvelope, clientArea, (AffineTransform)null);

            StyleBuilder sb = new StyleBuilder();
//            RasterSymbolizer symbolizer = sb.createRasterSymbolizer(sb.createColorMap(new String[]{"","",""}, new double[]{0.1,0.5,0.7}, new Color[]{new Color(0xE32600),new Color(0xFC9F00),new Color(0x69E003)},  ColorMap.TYPE_VALUES), 1.0);
            RasterSymbolizer symbolizer = new RasterSymbolizerImpl();

            renderer.paint(graphics, raster, symbolizer);
        } catch (FactoryException ex) {
            Exceptions.printStackTrace(ex);
        } catch (TransformException ex) {
            Exceptions.printStackTrace(ex);
        } catch (NoninvertibleTransformException ex) {
            Exceptions.printStackTrace(ex);
        }
//------------------------------------------------------------------------------
//-- /S-2
//------------------------------------------------------------------------------


//        RenderableImage renderableImage = raster.getRenderableImage(1,0);
//        RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//        RenderedImage renderedImage = renderableImage.createScaledRendering(clientArea.width, clientArea.height, hints);
//
//
////        try {
//
////        ImageWorker iw = new ImageWorker(raster.getRenderedImage());
//
////        PlanarImage pi = iw.getPlanarImage();
//
//
//
//
//        GeoPosition upleftpos = new GeoPosition(geometry.getCoordinate().y, geometry.getCoordinate().x);
//        final Point2D pointOnMap = mapViewer.getTileFactory().geoToPixel(upleftpos, mapViewer.getZoom());
//
//        Rectangle viewportBounds = mapViewer.getViewportBounds();
//
//        final int x = (int) (pointOnMap.getX() - viewportBounds.getX());
//        final int y = (int) (pointOnMap.getY() - viewportBounds.getY());
//
//        final int z = 10 / mapViewer.getZoom();
//
//
////        AffineTransform transform = new AffineTransform(z, 0, 0, z, x, y);
////        AffineTransform transform = new XAffineTransform(z, 1.0000000000000000001, 0.999999999999999999999, z, x, y);
//        AffineTransform transform = RendererUtilities.worldToScreenTransform(ReferencedEnvelope.EVERYTHING, clientArea);
//
//        RenderingHints hints = new Hints();
//
//        Envelope envelope = new Envelope(geometry.getCoordinate());
//        try {
//            GridCoverageRenderer gcr = new GridCoverageRenderer(DefaultGeographicCRS.WGS84, envelope, clientArea, hints);
//            gcr.paint(graphics, raster, new RasterSymbolizerImpl());
//        } catch (FactoryException ex) {
//            Exceptions.printStackTrace(ex);
//        } catch (TransformException ex) {
//            Exceptions.printStackTrace(ex);
//        } catch (NoninvertibleTransformException ex) {
//            Exceptions.printStackTrace(ex);
//        }

//        AffineTransform transform = AffineTransform.getTranslateInstance(x, y);

//        AffineTransform.getScaleInstance(mapViewer.getZoom(), mapViewer.getZoom());

//        graphics.drawRenderedImage(raster.getRenderedImage(), transform);
//            WarpTransform2D warpTransform = new WarpTransform2D(srcCoords, dstCoords, 0);
//
////            Geometry e2d = geometry.getEnvelope();
//            Envelope envelope = new Envelope(e2d.getCoordinate());
//            GridCoverageRenderer internal = new GridCoverageRenderer(DefaultGeographicCRS.WGS84, envelope , mapViewer.getBounds(), new AffineTransform() );
//            internal.paint(graphics, raster, new RasterSymbolizerImpl());
//        } catch (FactoryException ex) {
//            Exceptions.printStackTrace(ex);
//        } catch (TransformException ex) {
//            Exceptions.printStackTrace(ex);
//        } catch (NoninvertibleTransformException ex) {
//            Exceptions.printStackTrace(ex);
//        }
    }

    /**
     * Create a Style to display the specified band of the GeoTIFF image
     * as a greyscale layer.
     * <p>
     * This method is a helper for createGreyScale() and is also called directly
     * by the displayLayers() method when the application first starts.
     *
     * @param band the image band to use for the greyscale display
     *
     * @return a new Style instance to render the image in greyscale
     */
    private Style createGreyscaleStyle(int band) {
        ContrastEnhancement ce = sf.createContrastEnhancement();
        SelectedChannelType sct = sf.createSelectedChannelType(String.valueOf(band), ce);

        RasterSymbolizer sym = sf.getDefaultRasterSymbolizer();
        ChannelSelection sel = sf.createChannelSelection(new SelectedChannelType[]{sct});
        sym.setChannelSelection(sel);

        return SLD.builder.createStyle(sym);
    }

    /*
    Rectangle viewportBounds = mapViewer.getViewportBounds();


    GeoPosition geopoint = new GeoPosition(raster.getEnvelope2D().getMinX(), raster.getEnvelope2D().getMinY());
    Point2D point2D = mapViewer.getTileFactory().geoToPixel(geopoint, mapViewer.getZoom());
    int x = (int) (point2D.getX() - viewportBounds.getX());
    int y = (int) (point2D.getY() - viewportBounds.getY());

    ColorModel cm = new PaletteColorModel(palette);
    BufferedImage image = new BufferedImage(cm, (WritableRaster) raster.getRenderedImage().getData(), false, null);

    graphics.drawImage(image, x, y, new ImageObserver() {

    @Override
    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
    return true;
    }
    });
     *
     */
}
